<!DOCTYPE html>
<html lang="en">
    

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="format-detection" content="telephone=no">
    <meta name="keywords" content="RabbitMQ交换器类型与死信队列, RabbitMQ, 一缕轻风">
    <meta name="description" content="RabbitMQ常用的交换器类型RabbitMQ常用的交换器类型有fanout、direct、topic、headers这四种。AMQP协议里还提到另外两种类型：System和自定义，这里不予描述。对于这四种类型下面一一阐述。
fanout">
    <link rel="stylesheet" type="text/css" href="/blog/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/animate.css/animate.min.css">
    
    <!-- 是否加载使用自带的 prismjs. -->
    <link rel="stylesheet" href="/blog/libs/prism/prism-tomorrow-night.css">
    <link rel="stylesheet" type="text/css" href="/blog/libs/prism/prism-line-numbers.css">
    
    
    <!-- Material Icons -->
    <link rel="stylesheet" type="text/css" href="/blog/libs/materialicons/materialicons.css">
    
    <!-- Fontawesome Icons -->
    <link rel="stylesheet" type="text/css" href="/blog/libs/fontawesome/css/all.min.css">
    <!-- aos -->
    <link rel="stylesheet" type="text/css" href="/blog/libs/aos/aos.css">
    <!-- The theme css -->
    <link rel="stylesheet" type="text/css" href="/blog/css/xxcoding.css">

    
    <!-- Your css -->
    <link rel="stylesheet" type="text/css" href="/blog/css/my.css">
    
    <!-- 
        
            
                <link rel="stylesheet" type="text/css" href="/libs/fontawesome/css/all.min.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/animate.css/animate.min.css">
            
        
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/prism/prism-tomorrow-night.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/materialicons/materialicons.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/aplayer/APlayer.min.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/tocbot/tocbot.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/libs/aplayer/Meting.min.js">
            
        
            
                <link rel="stylesheet" type="text/css" href="/css/xxcoding.css">
            
        
            
                <link rel="stylesheet" type="text/css" href="/css/my.css">
            
        
     -->
    <!-- 
    <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500">
    
    <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css2?family=Marck+Script">
     -->
    

    <!-- Custom Head -->
    

    <title>RabbitMQ交换器类型与死信队列 | 一缕轻风</title>
    <link rel="icon" type="image/png" href="/blog/img/favicon.png">
    <script src="/blog/libs/jquery/jquery.min.js"></script>
<meta name="generator" content="Hexo 6.0.0"></head>

<body>
    <header class="navbar-fixed">
    <!-- <nav class="nav-extended pushpin"> -->
    <nav class="nav-color nav-transparent" id="nav-header" color-on-scroll="100">
        <div class="container">
            <div class="nav-wrapper">
                <a class="brand-logo waves-effect waves-light" href="/">
                    
                    <img src="/blog/img/logo.png" class="circle logo-img lazyload" data-src="/blog/img/logo.png" alt="logo">
                    
                    <span class="logo-span">一缕轻风</span>
                </a>
                <a href="#" data-target="nav-mobile" class="sidenav-trigger">
    <i class="material-icons">menu</i>
</a>
<ul class="right hide-on-med-and-down">
    
        
            <li>
                
                
                <a class="nav-item waves-effect waves-light" href="/" style="display: flex;">
                    <i class="material-icons">home</i>
                
                    <span class="nav-menu">首页</span>
                </a>
                
            </li>
        
    
        
            <li>
                
                
                <a class="nav-item waves-effect waves-light" href="/categories" style="display: flex;">
                    <i class="material-icons">chrome_reader_mode</i>
                
                    <span class="nav-menu">Categories</span>
                </a>
                
            </li>
        
    
        
            <li>
                
                
                <a class="nav-item waves-effect waves-light" href="/tags" style="display: flex;">
                    <i class="material-icons">label</i>
                
                    <span class="nav-menu">Tags</span>
                </a>
                
            </li>
        
    
        
            <li>
                
                
                <a class="nav-item waves-effect waves-light" href="/timeline" style="display: flex;">
                    <i class="material-icons">timeline</i>
                
                    <span class="nav-menu">时间线</span>
                </a>
                
            </li>
        
    
        
            <li>
                
                
                <a class="nav-item waves-effect waves-light" href="/about" style="display: flex;">
                    <i class="material-icons">account_circle</i>
                
                    <span class="nav-menu">关于</span>
                </a>
                
            </li>
        
    
    <li>
        <a class="nav-item modal-trigger waves-effect waves-light" href="#searchModal">
            <i class="material-icons">search</i>
            <!-- <i id="searchIcon" class="fas fa-search" title="Search" style="zoom: 0.6;"></i> -->
        </a>
    </li>
</ul>

            </div>
        </div>
    </nav>
</header>
<div class="sidenav" id="nav-mobile">
    <div class="user-view">
        <div class="background overlay">
            <img class="lazyload" src="/blog/img/bg/bg-1.jpg" data-src="/blog/img/bg/bg-1.jpg">
        </div>
        <img class="circle responsive-img lazyload" src="/blog/img/logo.png" data-src="/blog/img/logo.png">
        <div class="name white-text">一缕轻风</div>
        <div class="description white-text"></div>
    </div>
    <ul>
        
            
                <li>
                    
                    
                    <a class="waves-effect" href="/" style="display: flex;">
                        <i class="material-icons">home</i>
                    
                        <span>首页</span>
                    </a>
                    
                </li>
            
        
            
                <li>
                    
                    
                    <a class="waves-effect" href="/categories" style="display: flex;">
                        <i class="material-icons">chrome_reader_mode</i>
                    
                        <span>Categories</span>
                    </a>
                    
                </li>
            
        
            
                <li>
                    
                    
                    <a class="waves-effect" href="/tags" style="display: flex;">
                        <i class="material-icons">label</i>
                    
                        <span>Tags</span>
                    </a>
                    
                </li>
            
        
            
                <li>
                    
                    
                    <a class="waves-effect" href="/timeline" style="display: flex;">
                        <i class="material-icons">timeline</i>
                    
                        <span>时间线</span>
                    </a>
                    
                </li>
            
        
            
                <li>
                    
                    
                    <a class="waves-effect" href="/about" style="display: flex;">
                        <i class="material-icons">account_circle</i>
                    
                        <span>关于</span>
                    </a>
                    
                </li>
            
        
    </ul>
</div>


    <style>
    
    .post-content pre.line-numbers {
        padding: 2.2rem 1.5rem 0.5rem 3.8rem !important;
    }

    /* 行号位置 */
    .line-numbers .line-numbers-rows {
        top: 2.5rem;        /* 2.2rem + 0.3rem */
    }
    
    
    /* mac主题效果 */
    .post-content pre.line-numbers::after {
        content: '';
        position: absolute;
        display: block;
        border-radius: 50%;
        background: #ff5f56!important;
        width: 10px!important;
        height: 10px!important;
        top: 12px!important;
        left: 12px!important;
        -webkit-box-shadow: 16px 0 #ffbd2e, 32px 0 #27c93f;
        box-shadow: 16px 0 #ffbd2e, 32px 0 #27c93f;
    }
    
    
    /* 代码块语言 */
    .post-content pre.line-numbers::before {
        color: #ccc;
        font-size: .6rem;
        font-weight: 600;
        height: 25px;
        line-height: 25px;
        padding: 5px 10px 0;
        position: absolute;
        right: 0;
        text-align: right;
        top: 0;
        content: attr(data-language);
    }
    
</style>
<main>
    <!-- 文章封面 -->
    <div class="post-cover">
    <div class="cover-background">
        
        <div class="pattern repeat lazyload" data-src="/blog/img/icon-seamless.png"
            style="background-image: url('/blog/img/icon-seamless.png');">
            
        </div>
        
    </div>
    <div class="container">
        <div class="row">
            <div class="col-md-8">
                <div class="brand">
                    <h4>RabbitMQ交换器类型与死信队列</h4>
                </div>

            </div>
        </div>
    </div>
</div>

    <div class="container has-cover-container post-container">
        <div class="row">
            
                <div class="col s12 m12 l9" id="post-body">
                    <!-- 文章详情 -->
                    <div id="post-detail">
    <div class="card main main-raised">
        <div class="post-content">
            <h2 id="RabbitMQ常用的交换器类型"><a href="#RabbitMQ常用的交换器类型" class="headerlink" title="RabbitMQ常用的交换器类型"></a>RabbitMQ常用的交换器类型</h2><p>RabbitMQ常用的交换器类型有fanout、direct、topic、headers这四种。AMQP协议里还提到另外两种类型：System和自定义，这里不予描述。对于这四种类型下面一一阐述。</p>
<h3 id="fanout："><a href="#fanout：" class="headerlink" title="fanout："></a>fanout：</h3><p>它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。</p>
<h3 id="direct："><a href="#direct：" class="headerlink" title="direct："></a>direct：</h3><p>direct类型的交换器路由规则就是把消息路由到那些BindingKey和RoutingKey完全匹配的队列中。如下图：</p>
<img src="https://raw.githubusercontent.com/ice-matcha/DoubiBlog/master/resource/NeatReader-1609829465565.png" style="width: 100%; height: 100%;" />

<p>交换器的类型为direct，如果我们发送一条消息，并在发送消息的时候设置路由键为“warning”，则消息会路由到Queue1和Queue2，如果在发送消息的时候设置路由键为“info”或者“debug”，消息只会路由到Queue2。如果以其他的路由键发送消息，则消息不会路由到这两个队列中。</p>
<h3 id="topic："><a href="#topic：" class="headerlink" title="topic："></a>topic：</h3><p>topic类型的交换器在匹配规则上进行了扩展，它与direct类型的交换器相似，也是将消息路由到BindingKey和RoutingKey相匹配的队列中，但这里的匹配规则有些不同，约定如下：</p>
<ul>
<li>RoutingKey为一个点号<code>&quot;.&quot;</code>分隔的字符串（被点号<code>&quot;.&quot;</code>分隔开的每一段独立的字符串称为一个单词，如：”com.rabbitmq.client”、“com.hidden.client”</li>
<li>BindingKey和RoutingKey一样也是点号<code>&quot;.&quot;</code>分隔的字符串；</li>
<li>BindingKey中可以存在两种特殊字符串<code>&quot;*&quot;</code>和<code>&quot;#&quot;</code>，用于做模糊匹配，其中<code>&quot;*&quot;</code>用于匹配一个单词，<code>&quot;#&quot;</code>用于匹配多规格单词（可以是零个）。</li>
</ul>
<p>以下图为例：</p>
<img src="https://raw.githubusercontent.com/ice-matcha/DoubiBlog/master/resource/NeatReader-1609830205862.png" style="width: 100%; height: 100%;" />

<ul>
<li>路由键为”com.rabbitmq.client”的消息会同时路由到Queue1和Queue2；</li>
<li>路由键为”com.hidden.client”的消息只会路由到Queue2中；</li>
<li>路由键为”com.hidden.demo”的消息只会路由到Queue2中；</li>
<li>路由键为”java.rabbitmq.demo”的消息只会路由到Queue1中；</li>
<li>路由键为”java.util.concurrent”的消息将会被丢弃或者返回给生产者（需要设置mandatory参数），因为它没有匹配任何路由键。</li>
</ul>
<h3 id="headers："><a href="#headers：" class="headerlink" title="headers："></a>headers：</h3><p>headers类型的交换器不依赖于路由键的匹配规则来路由消息，而是根据发送的消息内容中的headers属性进行匹配。在绑定队列和交换器时制定一组键值对，当发送消息到交换器时，RabbitMQ会获取到该消息的headers（也是一个键值对的形式），对比其中的键值对是否完全匹配队列和交换器绑定时指定的键值对，如果完全匹配则消息会路由到该队列，否则不会路由到该队列。headers类型的交换器性能会很差，而且也不实用，基本上不会看到它的存在。</p>
<h2 id="死信队列"><a href="#死信队列" class="headerlink" title="死信队列"></a>死信队列</h2><p>DLX，全称为Dead-Letter-Exchange，可以称之为死信交换器，也有人称之为死信邮箱。当消息在一个队列中变成死信（dead message）之后，它能被重新被发送到另一个交换器中，这个交换器就是DLX，绑定DLX的队列就称之为死信队列。</p>
<p>消息变成死信一般是由于以下几种情况：</p>
<ul>
<li>消息被拒绝（Basic.Reject&#x2F;Basic.Nack），并且设置requeue参数为false；</li>
<li>消息过期；</li>
<li>队列达到最大长度。</li>
</ul>
<p>DLX也是一个正常的交换器，和一般的交换器没有区别，它能在任何的队列上被指定，实际上就是设置某个队列的属性。当这个队列中存 在死信时，RabbitMQ就会自动地将这个消息重新发布到设置的DLX上去，进而被路由到另一个队列，即死信队列。可以监听这个队列中的消息以进行相应的处理，这个特性与将消息的TTL设置为0配合使用可以弥补immediate参数的功能。</p>
<p>代码如下:</p>
<pre class="line-numbers language-php" data-language="php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span>
<span class="token keyword">require_once</span> <span class="token constant">__DIR__</span> <span class="token operator">.</span> <span class="token string single-quoted-string">'/../vendor/autoload.php'</span><span class="token punctuation">;</span>

<span class="token keyword">use</span> <span class="token package">PhpAmqpLib<span class="token punctuation">\</span>Connection<span class="token punctuation">\</span>AMQPStreamConnection</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">PhpAmqpLib<span class="token punctuation">\</span>Message<span class="token punctuation">\</span>AMQPMessage</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">PhpAmqpLib<span class="token punctuation">\</span>Wire<span class="token punctuation">\</span>AMQPTable</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 死信队列
 */</span>
<span class="token keyword">try</span><span class="token punctuation">&#123;</span>
    <span class="token variable">$connection</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AMQPStreamConnection</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'127.0.0.1'</span><span class="token punctuation">,</span> <span class="token number">5672</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'doubi'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'123456'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token variable">$channel</span> <span class="token operator">=</span> <span class="token variable">$connection</span><span class="token operator">-></span><span class="token function">channel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
	<span class="token comment">// 创建普通交换机</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">exchange_declare</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'exchange_normal'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'fanout'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 死信交换机</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">exchange_declare</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'exchange_dlx'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'direct'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 创建普通队列，并设置TTL和DLX</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">queue_declare</span><span class="token punctuation">(</span>
	    <span class="token string single-quoted-string">'queue_normal'</span><span class="token punctuation">,</span>
	    <span class="token constant boolean">false</span><span class="token punctuation">,</span>
	    <span class="token constant boolean">true</span><span class="token punctuation">,</span>
	    <span class="token constant boolean">false</span><span class="token punctuation">,</span>
	    <span class="token constant boolean">false</span><span class="token punctuation">,</span>
	    <span class="token constant boolean">false</span><span class="token punctuation">,</span>
	    <span class="token keyword">new</span> <span class="token class-name">AMQPTable</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
	        <span class="token string single-quoted-string">'x-message-ttl'</span><span class="token operator">=></span><span class="token number">15000</span><span class="token punctuation">,</span>	<span class="token comment">//ms</span>
	        <span class="token string single-quoted-string">'x-dead-letter-exchange'</span><span class="token operator">=></span><span class="token string single-quoted-string">'exchange_dlx'</span><span class="token punctuation">,</span>
	        <span class="token string single-quoted-string">'x-dead-letter-routing-key'</span><span class="token operator">=></span><span class="token string single-quoted-string">'dlx_key'</span>
	    <span class="token punctuation">]</span><span class="token punctuation">)</span>
	<span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 绑定</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">queue_bind</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue_normal'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'exchange_normal'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'normal_key'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 死信队列</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">queue_declare</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue_dlx'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// 绑定死信队列</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">queue_bind</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'queue_dlx'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'exchange_dlx'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'dlx_key'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">//向普通队列发送消息</span>
	<span class="token variable">$message</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AMQPMessage</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'hello world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token variable">$channel</span><span class="token operator">-></span><span class="token function">basic_publish</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">,</span><span class="token string single-quoted-string">'exchange_normal'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'normal_key'</span><span class="token punctuation">,</span> <span class="token constant boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

	<span class="token comment">// $channel->close();</span>
	<span class="token comment">// $connection->close();</span>

<span class="token punctuation">&#125;</span><span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name class-name-fully-qualified"><span class="token punctuation">\</span>Exception</span> <span class="token variable">$e</span><span class="token punctuation">)</span><span class="token punctuation">&#123;</span>
	<span class="token keyword">echo</span> <span class="token string double-quoted-string">"异常信息"</span><span class="token operator">.</span><span class="token variable">$e</span><span class="token operator">-></span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">&#125;</span>
</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>



<p>这里创建了两个交换器exchange_normal和exchange_dlx，分别绑定两个队列queue_normal 和queue_dlx。</p>
<p>由Web管理页面（下图）可以看出，两个队列都被标记了“D”，这个是durable的缩写，即设置了队列持久化。queue.normal这个队列还配置了TTL、DLX和DLK，其中DLK指的是x-dead-letter-routing-key这个属性。</p>
<img src="https://raw.githubusercontent.com/ice-matcha/DoubiBlog/master/resource/NeatReader-1616145433294.png" style="width: 100%; height: 100%;" />

<p>参考图下图，生产者首先发送一条携带路由键为“rk”的消息，然后经过交换器exchange.normal顺利地存储到队列queue.normal中。由于队列queue_normal设置了过期时间为15s，在这15s内没有消费者消费这条消息，那么判定这条消息为过期。由于设置了DLX，过期之时，消息被丢给交换器exchange_dlx中，这时找到与exchange_dlx匹配的队列queue_dlx，最后消息被存储在queue_dlx这个死信队列中。</p>
<img src="https://raw.githubusercontent.com/ice-matcha/DoubiBlog/master/resource/NeatReader-1616145418150.png" style="width: 100%; height: 100%;" />

<p>对于RabbitMQ来说，DLX是一个非常有用的特性。它可以处理异常情况下，消息不能够被消费者正确消费（消费者调用了Basic.Nack或者Basic.Reject）而被置入死信队列中的情况，后续分析程序可以通过消费这个死信队列中的内容来分析当时所遇到的异常情况，进而可以改善和优化系统。DLX配合TTL使用还可以实现延迟队列的功能。</p>
<h3 id="延迟队列"><a href="#延迟队列" class="headerlink" title="延迟队列"></a>延迟队列</h3><p>延迟队列存储的对象是对应的延迟消息，所谓“延迟消息”是指当消息被发送以后，并不想让消费者立刻拿到消息，而是等待特定时间后，消费者才能拿到这个消息进行消费。</p>
<p>延迟队列的使用场景有很多，如：</p>
<ul>
<li>在订单系统中，一个用户下单之后通常有30分钟的时间进行支付，如果30分钟之内没有支付成功，那么这个订单将进行异常处理，这时就可以使用延迟队列来处理这些订单了。</li>
<li>用户希望通过手机远程遥控家里的智能设备在指定的时间进行工作。这时候就可以将用户指令发送到延迟队列，当指令设定的时间到了再将指令推送到智能设备。</li>
</ul>
<p>在AMQP协议中，或者RabbitMQ本身没有直接支持延迟队列的功能，但是可以通过前面所介绍的DLX和TTL模拟出延迟队列的功能。</p>

        </div>
        <div class="post-comment">
            

    <style>
    .v[data-class=v] .vinput {
        padding: unset;
    }
</style>
<div id="vcomments"></div>

<script src="/blog/libs/valine/Valine.min.js"></script>

<script>
    new Valine({
        el: '#vcomments',
        appId: 'Mia2Oc0sFRP8CLKWIpkzlKH7-gzGzoHsz',
        appKey: 'UzWr1AJYRlfkoKpaNY9l2dIW',
        notify: 'false' === 'true',
        verify: 'false' === 'true',
        visitor: 'true' === 'true',
        avatar: 'monsterid',
        pageSize: '10',
        lang: '',
        // lang: 'en',
        placeholder: '发一条友善的评论',
        emojiCDN: 'https://i0.hdslb.com/bfs/emote/',
        emojiMaps: {
            "doge": "3087d273a78ccaff4bb1e9972e2ba2a7583c9f11.png",
            "微笑": "685612eadc33f6bc233776c6241813385844f182.png",
            "OK": "4683fd9ffc925fa6423110979d7dcac5eda297f4.png",
            "星星眼": "63c9d1a31c0da745b61cdb35e0ecb28635675db2.png",
            "妙啊": "b4cb77159d58614a9b787b91b1cd22a81f383535.png",
            "辣眼睛": "35d62c496d1e4ea9e091243fa812866f5fecc101.png",
            "吃瓜": "4191ce3c44c2b3df8fd97c33f85d3ab15f4f3c84.png",
            "滑稽": "d15121545a99ac46774f1f4465b895fe2d1411c3.png",
            "呲牙": "b5a5898491944a4268360f2e7a84623149672eb6.png",
            "打call": "431432c43da3ee5aab5b0e4f8931953e649e9975.png",
            "歪嘴": "4384050fbab0586259acdd170b510fe262f08a17.png",
            "调皮": "8290b7308325e3179d2154327c85640af1528617.png",
            "嗑瓜子": "28a91da1685d90124cfeead74622e1ebb417c0eb.png",
            "笑哭": "c3043ba94babf824dea03ce500d0e73763bf4f40.png",
            "脱单doge": "bf7e00ecab02171f8461ee8cf439c73db9797748.png",
            "给心心": "1597302b98827463f5b75c7cac1f29ea6ce572c4.png",
            "嘟嘟": "abd7404537d8162720ccbba9e0a8cdf75547e07a.png",
            "喜欢": "8a10a4d73a89f665feff3d46ca56e83dc68f9eb8.png",
            "酸了": "92b1c8cbceea3ae0e8e32253ea414783e8ba7806.png",
            "哦呼": "362bded07ea5434886271d23fa25f5d85d8af06c.png",
            "嫌弃": "de4c0783aaa60ec03de0a2b90858927bfad7154b.png",
            "大哭": "2caafee2e5db4db72104650d87810cc2c123fc86.png",
            "害羞": "9d2ec4e1fbd6cb1b4d12d2bbbdd124ccb83ddfda.png",
            "疑惑": "b7840db4b1f9f4726b7cb23c0972720c1698d661.png",
            "喜极而泣": "485a7e0c01c2d70707daae53bee4a9e2e31ef1ed.png",
            "奸笑": "bb84906573472f0a84cebad1e9000eb6164a6f5a.png",
            "笑": "81edf17314cea3b48674312b4364df44d5c01f17.png",
            "偷笑": "6c49d226e76c42cd8002abc47b3112bc5a92f66a.png",
            "惊讶": "f8e9a59cad52ae1a19622805696a35f0a0d853f3.png",
            "捂脸": "6921bb43f0c634870b92f4a8ad41dada94a5296d.png",
            "阴险": "ba8d5f8e7d136d59aab52c40fd3b8a43419eb03c.png",
            "囧": "12e41d357a9807cc80ef1e1ed258127fcc791424.png",
            "呆": "33ad6000d9f9f168a0976bc60937786f239e5d8c.png",
            "抠鼻": "cb89184c97e3f6d50acfd7961c313ce50360d70f.png",
            "大笑": "ca94ad1c7e6dac895eb5b33b7836b634c614d1c0.png",
            "惊喜": "0afecaf3a3499479af946f29749e1a6c285b6f65.png",
            "无语": "44667b7d9349957e903b1b62cb91fb9b13720f04.png",
            "点赞": "1a67265993913f4c35d15a6028a30724e83e7d35.png",
            "鼓掌": "895d1fc616b4b6c830cf96012880818c0e1de00d.png",
            "尴尬": "cb321684ed5ce6eacdc2699092ab8fe7679e4fda.png",
            "灵魂出窍": "43d3db7d97343c01b47e22cfabeca84b4251f35a.png",
            "委屈": "d2f26cbdd6c96960320af03f5514c5b524990840.png",
            "傲娇": "010540d0f61220a0db4922e4a679a1d8eca94f4e.png",
            "疼": "905fd9a99ec316e353b9bd4ecd49a5f0a301eabf.png",
            "冷": "cb0ebbd0668640f07ebfc0e03f7a18a8cd00b4ed.png",
            "生病": "0f25ce04ae1d7baf98650986454c634f6612cb76.png",
            "吓": "9c10c5ebc7bef27ec641b8a1877674e0c65fea5d.png",
            "吐": "06946bfe71ac48a6078a0b662181bb5cad09decc.png",
            "捂眼": "c5c6d6982e1e53e478daae554b239f2b227b172b.png",
            "嘘声": "e64af664d20716e090f10411496998095f62f844.png",
            "思考": "cfa9b7e89e4bfe04bbcd34ccb1b0df37f4fa905c.png",
            "再见": "fc510306bae26c9aec7e287cdf201ded27b065b9.png",
            "翻白眼": "eba54707c7168925b18f6f8b1f48d532fe08c2b1.png",
            "哈欠": "888d877729cbec444ddbd1cf4c9af155a7a06086.png",
            "奋斗": "bb2060c15dba7d3fd731c35079d1617f1afe3376.png",
            "墨镜": "3a03aebfc06339d86a68c2d893303b46f4b85771.png",
            "难过": "a651db36701610aa70a781fa98c07c9789b11543.png",
            "撇嘴": "531863568e5668c5ac181d395508a0eeb1f0cda4.png",
            "抓狂": "4c87afff88c22439c45b79e9d2035d21d5622eba.png",
            "生气": "3195714219c4b582a4fb02033dd1519913d0246d.png",
            "口罩": "3ad2f66b151496d2a5fb0a8ea75f32265d778dd3.png",
            "牛年": "9275275ff1f2659310648221107d20bc4970f106.png",
            "福到了": "5de5373d354c373cf1617b6b836f3a8d53c5a655.png",
            "鸡腿": "c7860392815d345fa69c4f00ef18d67dccfbd574.png",
            "月饼": "89b19c5730e08d6f12fadf6996de5bc2e52f81fe.png",
            "雪花": "a41813c4edf8782047e172c884ebd4507ce5e449.png",
            "视频卫星": "dce6fc7d6dfeafff01241924db60f8251cca5307.png",
            "干杯": "8da12d5f55a2c7e9778dcc05b40571979fe208e6.png",
            "爱心": "ed04066ea7124106d17ffcaf75600700e5442f5c.png",
            "锦鲤": "643d6c19c8164ffd89e3e9cdf093cf5d773d979c.png",
            "胜利": "b49fa9f4b1e7c3477918153b82c60b114d87347c.png",
            "加油": "c7aaeacb21e107292d3bb053e5abde4a4459ed30.png",
            "抱拳": "89516218158dbea18ab78e8873060bf95d33bbbe.png",
            "响指": "1b5c53cf14336903e1d2ae3527ca380a1256a077.png",
            "保佑": "fafe8d3de0dc139ebe995491d2dac458a865fb30.png",
            "支持": "3c210366a5585706c09d4c686a9d942b39feeb50.png",
            "拥抱": "41780a4254750cdaaccb20735730a36044e98ef3.png",
            "跪了": "f2b3aee7e521de7799d4e3aa379b01be032698ac.png",
            "怪我咯": "07cc6077f7f7d75b8d2c722dd9d9828a9fb9e46d.png",
            "黑洞": "e90ec4c799010f25391179118ccd9f66b3b279ba.png",
            "老鼠": "8e6fb491eb1bb0d5862e7ec8ccf9a3da12b6c155.png",
            "凛冬-生气": "d90bd2fbc13a3cb8d313f6d675f20caf109f60a7.png",
            "W-哈哈": "83d527303c8f62f494e6971c48836487e7d87b1b.png",
            "霜叶-疑问": "ada3aea8594e724511c1daad15fb3b23900d8e24.png",
            "煌-震撼": "7bb39ac289bc97fe52af047020a9bf324ecdebe1.png",
            "哭泣": "a61abafb8c39defc323b045f30072198007b1c89.png",
            "狗子": "6a997106af5bf490f22c80a7acf3be813ee755fc.png",
            "羞羞": "f4f9171e4d8c3f30827a8b96ea1ce1beb825ad50.png",
            "亲亲": "2f72bae7b834d499f259c833f7011d5ed8748fd1.png",
            "耍帅": "d7a38b08d1f1cc35b19c35041f29ffcc48808e87.png",
            "气愤": "069b029d17a086ab475fd331697a649e234850bb.png",
            "高兴": "416570a8aca7be12fb2c36e4b846906653f6d294.png",
        }
    })
</script>



        </div>

    </div>
</div>

                </div>
                <div class="col l3" id="toc-body">
                    <!-- 文章目录 -->
                    <link rel="stylesheet" href="/blog/libs/tocbot/tocbot.css">
<style>
    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget #toc-title {
        padding: 35px 0 15px 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    #toc-content .toc-list {
        padding-left: 10px;
    }

    #toc-content {
        padding-bottom: 30px;
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ul li, #toc-content ol li {
        padding-left: 10px;
        line-height: 1.8rem;
        font-size: 1rem;
        color: #444;
    }

    #toc-content .is-active-link {
        color: #E91E63;
    }

    #toc-content .is-active-link::before {
        background-color: transparent;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
    }

    .toc-widget {
        box-shadow: 0 16px 24px 2px rgb(0 0 0 / 14%), 0 6px 30px 5px rgb(0 0 0 / 12%), 0 8px 10px -5px rgb(0 0 0 / 20%);
    }

</style>
<div id="post-toc">
    <div class="toc-widget card">
        <div id="toc-title">
            <i class="far fa-list-alt"></i>&nbsp;&nbsp;目录
        </div>
        <div id="toc-content"></div>
    </div>
</div>
<script src="/blog/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function() {
        tocbot.init({
            // Where to render the table of contents.
            tocSelector: '#toc-content',
            // Where to grab the headings to build the table of contents.
            contentSelector: '.post-content',
            // Which headings to grab inside of the contentSelector element.
            headingSelector: 'h1, h2, h3, h4',
            // For headings inside relative or absolute positioned containers within content.
            hasInnerContainers: false,
            // Smooth scrolling enabled.
            scrollSmooth: true,
            // Smooth scroll duration.
            scrollSmoothDuration: 420,
            headingsOffset: $('#nav-header').height() + 10,
            scrollSmoothOffset: -($('#nav-header').height() + 10),
            collapseDepth: 4,
            // orderedList can be set to false to generate unordered lists (ul)
            // instead of ordered lists (ol)
            orderedList: false,
        });

        // 动态设置文章目录的宽度， 防止滚动和窗口变动时变形
        // width()不包含padding, innerWidth()包含padding
        $('.toc-widget').width($('#toc-body').width());

        let tocHeight = parseInt($(window).height() * 0.5 - 64);
        let $tocWidget = $('.toc-widget');
        let $tocTitle = $('#toc-title');
        let $tocContent = $('#toc-content');
        if ($(window).scrollTop() > tocHeight) {
            $tocWidget.addClass('toc-fixed');
        } else {
            $tocWidget.removeClass('toc-fixed');
        }
        $tocWidget.css('max-height', $(window).height() * 0.6);
        if ($tocContent.height() > ($tocWidget.height() - $tocTitle.height())) {
            $tocWidget.css('overflow-y', 'auto');
        }
        // if ($tocWidget.height() > $(window).height() * 0.6) {
        //     $tocWidget.css('max-height', $(window).height() * 0.6);
        // }
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
            if ($tocContent.height() > ($tocWidget.height() - $tocTitle.height())) {
                $tocWidget.css('overflow-y', 'auto');
            } else {
                $tocWidget.css('overflow-y', 'unset');
            }
            $('.toc-widget').width($('#toc-body').width());
        });
        $(window).on('resize', function(){
            $tocWidget.css('max-height', $(window).height() * 0.6);
            if ($tocContent.height() > ($tocWidget.height() - $tocTitle.height())) {
                $tocWidget.css('overflow-y', 'auto');
            } else {
                $tocWidget.css('overflow-y', 'unset');
            }
            $('.toc-widget').width($('#toc-body').width());
        });
    });
</script>

                </div>
            
        </div>
    </div>
</main>

    <footer class="page-footer footer-color">
    
        
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.css">


<style type="text/css">
    .aplayer.aplayer-fixed {
        z-index: 999;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    

    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #b7daff;
    }
</style>

<div class="">
    <div class="row">
        <meting-js
            class="col l8 offset-l2 m10 offset-m1 s12"
            server="netease"
            type="playlist"
            id="743950282"
            fixed='true'
            autoplay='false'
            theme='#b7daff'
            loop='all'
            order='random'
            preload='auto'
            volume='0.7'
            list-folded='true'>
        </meting-js>
    </div>
</div>


<script src="https://cdn.jsdelivr.net/npm/aplayer@1.10.1/dist/APlayer.min.js"></script>


<script src="https://cdn.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"></script>


    
    <div class="container">
        <div class="row center">
            <div class="col l12 m12 s12">
                <div id="framework-info">
                    Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
                    &nbsp;
                </div>
                <div id="siteinfo">
                    <!-- <span>站点总字数：</span> -->
                    
                </div>
                
                <div id="sitetime">载入运行时间...</div>
                <script>
                    function siteTime() {
                        var seconds = 1000;
                        var minutes = seconds * 60;
                        var hours = minutes * 60;
                        var days = hours * 24;
                        var years = days * 365;
                        var today = new Date();
                        var startYear = "2021";
                        var startMonth = "2";
                        var startDate = "19";
                        var startHour = "0";
                        var startMinute = "0";
                        var startSecond = "0";
                        var todayYear = today.getFullYear();
                        var todayMonth = today.getMonth() + 1;
                        var todayDate = today.getDate();
                        var todayHour = today.getHours();
                        var todayMinute = today.getMinutes();
                        var todaySecond = today.getSeconds();
                        var t1 = Date.UTC(startYear, startMonth, startDate, startHour, startMinute, startSecond);
                        var t2 = Date.UTC(todayYear, todayMonth, todayDate, todayHour, todayMinute, todaySecond);
                        var diff = t2 - t1;
                        var diffYears = Math.floor(diff / years);
                        var diffDays = Math.floor((diff / days) - diffYears * 365);
                        var diffHours = Math.floor((diff - (diffYears * 365 + diffDays) * days) / hours);
                        var diffMinutes = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours) /
                            minutes);
                        var diffSeconds = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours -
                            diffMinutes * minutes) / seconds);
                        if (startYear == todayYear) {
                            document.getElementById("year").innerHTML = todayYear;
                            document.getElementById("sitetime").innerHTML = "本站已持续运行 " + "<span class='white-text'>" + diffDays + "</span>" + " 天 "
                            + "<span class='white-text'>" + diffHours + "</span>" + " 小时 "
                            + "<span class='white-text'>" + diffMinutes + "</span>" + " 分钟 "
                            + "<span class='white-text'>" + diffSeconds + "</span>" + " 秒";
                        } else {
                            document.getElementById("year").innerHTML = startYear + " - " + todayYear;
                            document.getElementById("sitetime").innerHTML = "本站已持续运行 " + "<span class='white-text'>" + diffYears + "</span>" + " 年 "
                            + "<span class='white-text'>" + diffDays + "</span>" + " 天 "
                            + "<span class='white-text'>" + diffHours + "</span>" + " 小时 "
                            + "<span class='white-text'>" + diffMinutes + "</span>" + " 分钟 "
                            + "<span class='white-text'>" + diffSeconds + "</span>" + " 秒";
                        }
                    }
                    setInterval(siteTime, 1000);
                </script>
                
                
                
            </div>
        </div>
    </div>
    <div class="footer-copyright">
        <div class="container center">
            Copyright&nbsp;&copy;
            
                <span id="year">2021 - 2022</span>
            
            ,&nbsp;
            made with <span style="color: red;">❤️</span>&nbsp;&nbsp;by
            <a href="/blog/about" target="_blank">ice-matcha</a>
            for a better web.
        </div>
    </div>
</footer>


    
    <!-- 回到顶部按钮 -->
<div id="back-top" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>

    

    <script src="/blog/libs/materialize/materialize.min.js"></script>
<script src="/blog/libs/lazyload/lazyload.min.js"></script>
<script src="/blog/libs/aos/aos.js"></script>
<script src="/blog/js/xxcoding.js"></script>


<script src="https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js"></script>


</body>
</html>
